import ResizeObserver from 'resize-observer-polyfill'

export const ratePixel = (px = 0) =>
	(parseFloat(document.documentElement.style.fontSize) / 75) * px

export const clipboard = (text) =>
	new Promise((resolve, reject) => {
		const input = text
		const el = document.createElement('textarea')
		el.value = input
		el.setAttribute('readonly', '')
		el.style.contain = 'strict'
		el.style.position = 'absolute'
		el.style.left = '-9999px'
		el.style.fontSize = '12pt' // Prevent zooming on iOS

		const selection = getSelection()
		let originalRange = false
		if (selection.rangeCount > 0) {
			originalRange = selection.getRangeAt(0)
		}
		document.body.appendChild(el)
		el.select()
		el.selectionStart = 0
		el.selectionEnd = input.length

		let success = false
		try {
			success = document.execCommand('copy')
		} catch (err) {}

		document.body.removeChild(el)

		if (originalRange) {
			selection.removeAllRanges()
			selection.addRange(originalRange)
		}

		success ? resolve() : reject(new Error())
	})

/**
 * 解析json字符串
 * @param {*} jsonStr
 * @returns
 */
export const parseJSON = (jsonStr = '{}', errData = {}) => {
	try {
		if (!jsonStr) {
			return errData
		}
		return JSON.parse(jsonStr) || errData
	} catch {
		return errData
	}
}

/**
 * 解析日期
 * @param {*} dateStr
 * @returns Date对象
 */
export const parseDate = (dateStr) => {
	if (!dateStr) {
		return null
	}
	let date = new Date(dateStr)
	if (date instanceof Date && !isNaN(date)) {
		return date
	}
	if (Object.prototype.toString.call(dateStr) === '[object String]') {
		dateStr = String(dateStr).replace(/-/g, '/')
		date = new Date(dateStr)
		if (date instanceof Date && !isNaN(date)) {
			return date
		}
	}
	return null
}

/**
 * 监控DOM尺寸改变
 * @param {*} el
 * @param {*} cb
 * @returns
 */
export const observeDOM = (el, watchType = 'both', cb) => {
	if (!el || !cb) {
		return
	}
	// 监控时立马执行一遍
	cb && cb()

	let mutationObserver
	let resizeObserver

	if (['both', 'mutation'].includes(watchType)) {
		mutationObserver = new MutationObserver(
			() => cb && window.requestAnimationFrame(cb)
		)
		mutationObserver.observe(el, {
			attributes: true, // 监控属性变化
			subtree: true,
			characterData: true, // 监控节点内容或节点文本的变动
			characterDataOldValue: true,
			attributeOldValue: true,
			childList: true,
			// attributeFilter: [],
		})
	}
	if (['both', 'resize'].includes(watchType)) {
		resizeObserver = new ResizeObserver((entries) => {
			// eslint-disable-next-line
			for (const entry of entries) {
				// 可以通过 判断 entry.target得知当前改变的 Element，分别进行处理。
				window.requestAnimationFrame(() => {
					cb && cb()
				})
			}
		})
		resizeObserver.observe(el)
	}

	return () => {
		mutationObserver && mutationObserver.disconnect()
		resizeObserver && resizeObserver.disconnect()
	}
}

/**
 * 防抖
 * @param {*} func
 * @param {*} wait
 * @param {*} immediate
 * @returns
 */
export const debounce = (func, wait, immediate) => {
	let timeout, args, context, timestamp, result
	const later = () => {
		const last = +new Date() - timestamp
		if (last < wait && last >= 0) {
			timeout = setTimeout(later, wait - last)
		} else {
			timeout = null
			if (!immediate) {
				result = func.apply(context, args)
				if (!timeout) context = args = null
			}
		}
	}
	return function () {
		context = this
		args = arguments
		timestamp = new Date()
		const callNow = immediate && !timeout
		if (!timeout) timeout = setTimeout(later, wait)
		if (callNow) {
			result = func.apply(context, args)
			context = args = null
		}
		return result
	}
}

/**
 * 节流
 * @param {*} func
 * @param {*} wait
 * @param {*} options
 * @returns
 */
export const throttle = (func, wait, options) => {
	let context, args, result
	let timeout = null
	let previous = 0
	if (!options) options = {}
	const later = () => {
		previous = options.leading === false ? 0 : +new Date()
		timeout = null
		result = func.apply(context, args)
		if (!timeout) context = args = null
	}
	return function () {
		const now = +new Date()
		if (!previous && options.leading === false) previous = now
		const remaining = wait - (now - previous)
		context = this
		args = arguments
		if (remaining <= 0 || remaining > wait) {
			if (timeout) {
				clearTimeout(timeout)
				timeout = null
			}
			previous = now
			result = func.apply(context, args)
			if (!timeout) context = args = null
		} else if (!timeout && options.trailing !== false) {
			timeout = setTimeout(later, remaining)
		}
		return result
	}
}

/**
 * 判断是否为iphone刘海屏
 * @returns
 */
export const isIphoneX = () => {
	const isIphoneX =
		/iphone/gi.test(window.navigator.userAgent) &&
		window.devicePixelRatio &&
		(window.devicePixelRatio === 3 || window.devicePixelRatio === 2) &&
		window.screen.width === 375 &&
		(window.screen.height === 812 || window.screen.height === 724)
	const isIphoneXr =
		/iphone/gi.test(window.navigator.userAgent) &&
		window.devicePixelRatio &&
		window.devicePixelRatio === 2 &&
		window.screen.width === 414 &&
		(window.screen.height === 896 || window.screen.height === 808)
	const isIphoneXsMax =
		/iphone/gi.test(window.navigator.userAgent) &&
		window.devicePixelRatio &&
		window.devicePixelRatio === 3 &&
		window.screen.width === 414 &&
		(window.screen.height === 896 || window.screen.height === 808)
	return isIphoneX || isIphoneXr || isIphoneXsMax
}

/**
 * 兼容处理iphoneX底部横条问题
 * @param {*} fixedDom
 * @param {*} contentDom
 * @param {*} bgColor
 */
export const fixedIOSX = (fixedDom, contentDom, bgColor) => {
	try {
		if (isIphoneX()) {
			const metas = document.getElementsByTagName('meta')
			for (let i = 0; i < metas.length; i++) {
				if (
					metas[i].name == 'viewport' &&
					metas[i].content.indexOf('viewport-fit=cover') == -1
				) {
					metas[i].content = metas[i].content + ',viewport-fit=cover'
					break
				}
			}
			if (fixedDom) {
				const menu = document.querySelector(fixedDom)
				if (menu) {
					menu.style.height = 'auto'
					//menu.style.backgroundColor = '#AFAFB5';
					menu.style.paddingBottom = '34px'

					if (bgColor) menu.style.backgroundColor = bgColor
					if (contentDom) {
						const fixedMenuHeight = menu.offsetHeight + 'px'
						const contents = document.querySelectorAll(contentDom)
						if (contents) {
							for (let i = 0; i < contents.length; i++) {
								const content = contents[i]
								if (
									parseInt(getComputedStyle(content).bottom)
								) {
									content.style.bottom = fixedMenuHeight
								} else if (
									parseInt(
										getComputedStyle(content).paddingBottom
									)
								) {
									content.style.paddingBottom =
										fixedMenuHeight
								} else {
									content.style.marginBottom = fixedMenuHeight
								}
							}
						}
					}
				}
			}
		}
	} catch (e) {}
}

/**
 * 预加载图片列表
 * @param {*} imageList
 * @returns
 */
export const preloadImages = (imageList = []) => {
	const promises = []

	for (let i = 0; i < imageList.length; i++) {
		const src = imageList[i]
		const promise = new Promise((resolve, reject) => {
			const image = new Image()
			image.onload = resolve
			image.onerror = reject
			image.src = src
		})

		promises.push(promise)
	}

	return Promise.all(promises)
}

/**
 * 企微pc端侧边栏添加左上角返回上一页按钮
 * @param {*} sdk
 * @param {*} opt
 */
export const backToHistoryBtn = (sdk, opt = {}) => {
	//判断jsdk的gContext方法、企微环境、pc环境、历史记录、页面referrer
	if (
		!sdk.gContext ||
		// !sdk._ext.IsWWBiz ||
		(!sdk.isWinPC && !sdk.isMac) ||
		window.history.length <= 1 ||
		window.history.state?.position === 0 ||
		!document.referrer
	) {
		return false
	}
	const _addBtnDom = () => {
		//是pc端侧边栏时添加返回按钮dom
		let par = {
			btnStyle: '', //按钮css样式
			btnTxt: '返回上页', //按钮文案
			//左侧icon图片url 或者 base64文件
			iconSrc:
				'',
		}
		if (opt && Object.keys(opt)) {
			par = Object.assign(par, opt)
		}
		sdk.dWait(
			() => document.body,
			() => {
				const dom =
					document.querySelector('#backToHistoryBtn_ext') || null
				if (dom) {
					dom._handleMousedown &&
						dom.removeEventListener(
							'mousedown',
							dom._handleMousedown
						)
					dom._handleMousemove &&
						document.removeEventListener(
							'mousemove',
							dom._handleMousemove
						)
					dom._handleMouseup &&
						document.removeEventListener(
							'mouseup',
							dom._handleMouseup
						)
					dom.remove() //如果存在先删除
				}
				const backDom = document.createElement('div')
				const minTop = 0
				const maxTop = 300
				let top = localStorage.getItem('_backBtn_top_')
					? Number(localStorage.getItem('_backBtn_top_'))
					: 150
				backDom.id = 'backToHistoryBtn_ext'
				backDom.style = `width: 105px;height: 40px;line-height: 40px;position: fixed; top: ${top}px;left:-1px;z-index: 99;user-select: none;display: flex; align-items: center;border-radius: 0 20px 20px 0;cursor: pointer; color: #fff;font-size: 16px;background-color: rgba(216,42,43,0.7);font-weight: 500;${par.btnStyle}`
				let offsetY
				let isDragging = false
				let isClick = false

				// 鼠标按下时开始拖动
				backDom.addEventListener(
					'mousedown',
					(backDom._handleMousedown = (event) => {
						offsetY = event.offsetY
						top = isFinite(Number(backDom.style.top))
							? Number(backDom.style.top)
							: 150
						isDragging = true
						isClick = true
					})
				)
				// 鼠标移动时更新元素位置
				document.addEventListener(
					'mousemove',
					(backDom._handleMousemove = (event) => {
						if (isDragging) {
							const newTop = Math.max(
								minTop,
								Math.min(maxTop, event.clientY - offsetY)
							)
							const deltaY = newTop - top
							backDom.style.top = `${newTop}px`
							isClick = Math.abs(deltaY) <= 2
							localStorage.setItem('_backBtn_top_', newTop)
						}
					})
				)
				// 鼠标释放时停止拖动
				document.addEventListener(
					'mouseup',
					(backDom._handleMouseup = () => {
						if (!isDragging || !isClick) {
							isDragging = false
							return
						}
						isClick = false
						isDragging = false
						const pagePath = location.pathname.replace(
							/(\/prp\/[^/]+)/i,
							''
						)
						const isSelf = document.referrer
							.split('?')[0]
							.includes(pagePath) //若referrer和当前url相等
						window.history.go(isSelf ? -2 : -1)
						setTimeout(() => {
							//执行go(-1)前和后的页面地址相同，则隐藏返回按钮
							const newPath = location.pathname.replace(
								/(\/prp\/[^/]+)/i,
								''
							)
							if (
								(newPath === pagePath ||
									history.state.position === 0) &&
								backDom
							) {
								backDom._handleMousedown &&
									backDom.removeEventListener(
										'mousedown',
										backDom._handleMousedown
									)
								backDom._handleMousemove &&
									document.removeEventListener(
										'mousemove',
										backDom._handleMousemove
									)
								backDom._handleMouseup &&
									document.removeEventListener(
										'mouseup',
										backDom._handleMouseup
									)
								backDom.remove()
							}
						}, 500)
					})
				)

				backDom.innerHTML = `<img style='margin: 0 5px 0 10px;width: 10px;vertical-align: middle;' src="${par.iconSrc}" alt=''/><span>${par.btnTxt}</span>`
				document.body.appendChild(backDom)
			},
			10 * 1000,
			1000
		)
	}

	//判断是否是侧边栏
	sdk.gContext(function (res) {
		if (
			res &&
			[
				'contact_profile',
				'single_chat_tools',
				'group_chat_tools',
			].includes(res.type)
		) {
			_addBtnDom() // 侧边栏执行
		}
	})
}
